package excel_templates

import (
	"bytes"
	"fmt"
	"net/http"
	"net/url"
	"time"

	"github.com/xuri/excelize/v2"
)

// 生成 Excel 列字母序列
// GenerateExcelColumns("A", "D") 会返回 ["A", "B", "C", "D"]。
func GenerateExcelColumns(start, end string) []string {
	startCol := int(start[0] - 'A')
	endCol := int(end[0] - 'A')
	var columns []string
	for i := startCol; i <= endCol; i++ {
		columns = append(columns, string(rune('A'+i)))
	}
	return columns
}

// ParseDateOrDefault 将时间字符串解析为 time.Time。
// 如果格式不正确，则返回当天的时间。
// layout 在函数内部定义为固定格式。
func ParseDateOrDefault(dateStr string) time.Time {
	// 定义固定的时间格式
	layout := "2006-01-02 15:04:05"
	// 尝试解析传入的日期字符串
	t, err := time.Parse(layout, dateStr)
	if err != nil {
		// 如果解析失败，返回当前时间
		return time.Now()
	}
	// 如果解析成功，返回解析后的时间
	return t
}

// GetDateComponents 返回传入时间的年份、月份和日期
func GetDateComponents(t time.Time) (int, int, int) {
	// 返回年份、月份和日期
	return t.Year(), int(t.Month()), t.Day()
}

// SetCellValue 根据值的类型设置 Excel 单元格的值
func SetCellValue(f *excelize.File, sheetName, tag, rowStr string, value interface{}) {
	switch value := value.(type) {
	case int:
		f.SetCellInt(sheetName, tag+rowStr, value)
	case float64:
		f.SetCellFloat(sheetName, tag+rowStr, value, 4, 64)
	case string:
		f.SetCellStr(sheetName, tag+rowStr, value)
	case bool:
		f.SetCellBool(sheetName, tag+rowStr, value)
	default:
		f.SetCellStr(sheetName, tag+rowStr, "")
	}
}

// FillExcelWithData 填充 Excel 表格
func FillExcelWithData(
	f *excelize.File,
	sheetName string,
	list []map[string]interface{},
	start_col, end_col string,
	data_start_row int,
) error {
	// 遍历 list 中的每个 map
	for _, item := range list {
		row_str := fmt.Sprintf("%d", data_start_row)

		// 复制当前行格式
		f.DuplicateRow(sheetName, data_start_row)

		// 遍历生成的列标签
		for _, tag := range GenerateExcelColumns(start_col, end_col) {
			// 获取单元格的值
			cellValue, err := f.GetCellValue(sheetName, tag+row_str)
			if err != nil {
				continue
			}

			// 获取 map 中对应的值
			value := item[cellValue]
			// 设置单元格的值
			SetCellValue(f, sheetName, tag, row_str, value)
		}

		// 移动到下一行
		data_start_row++
	}

	// 删除最后一行数据（因为数据是从 data_start_row 开始的，所以删除 data_start_row）
	f.RemoveRow(sheetName, data_start_row)

	return nil
}

// WriteExcelToBuffer 将 Excel 文件写入缓冲区，并返回字节数据
func WriteExcelToBuffer(f *excelize.File) ([]byte, error) {
	var buf bytes.Buffer
	if _, err := f.WriteTo(&buf); err != nil {
		return nil, fmt.Errorf("failed to write Excel data to buffer: %v", err)
	}
	return buf.Bytes(), nil
}

// WriteExcelResponse 发送 Excel 文件给 HTTP 响应
func WriteExcelResponse(w http.ResponseWriter, filename string, data []byte) {
	// 设置 HTTP 头信息，指定为 Excel 文件
	w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
	w.Header().Set("Content-Length", fmt.Sprintf("%d", len(data))) // 设置文件大小

	// 将 Excel 数据写入 HTTP 响应流
	w.Write(data)
}

// GenerateExcelFilename 生成带日期的 Excel 文件名 --医院科室直接成本表// GenerateExcelFilename 生成带日期的 Excel 文件名，并进行 URL 编码
func GenerateExcelFilename(prefix string) string {
	filename := fmt.Sprintf("%s%s.xlsx", prefix, time.Now().Format("20060102"))
	return url.QueryEscape(filename) // 进行 URL 编码，避免中文乱码
}
